/**
* @file        vector_buff
* @brief       
* @version     1.0.0
* @author      Changlin.Jing 
* @date        2022/10/19 19:37
* @copyright   Copyright  2022 Langge Software Co., Ltd. All rights reserved.
*/
#ifndef LANGGEBASE_VECTOR_BUFF_H
#define LANGGEBASE_VECTOR_BUFF_H
#include <vector>
#include "ut_symbols.h"
#include <math.h>
BEGIN_SPACE_LANGE_VDR
template<typename T1,typename T2>
class VectorBuffer{
public:
    /***
     * @param dims 缓存维度
     * @param size 缓存长度
     * @param isTimeIdex 设置是否需要时间索引
     */
    VectorBuffer(std::uint32_t dims,std::uint32_t size,bool isTimeIdex);

    ~VectorBuffer();

    void init();

    void clear();

    void reset();

public:

    /***
     * 加入缓存函数（不需要时间索引）
     * @param data
     */
    void addData(std::vector<T2> data);

    /***
     * 加入缓存数据 需要时间索引
     * @param timeIndex
     * @param data
     */
    void addData(T1 timeIndex,std::vector<T2> data);

    /**
     * 判定是否已经到了最大长度
     * @return
     */
    bool isFull();

    /**
     * 获取对应时间索引的数据，查找不到 返回 nullptr
     * @param timeIndex
     * @param ret
     */
    void getDataByTimeIndex(T1 timeIndex,std::vector<T2> &ret);

    /**
     * 获取最近 index 个缓存
     * @param index
     * @param ret
     */
    void getDataByIndexFromLast(std::uint32_t index,std::vector<T2> &ret);

    void  getLastNDataByColumnIndex(std::vector<T2>& res,std::uint32_t count,std::uint32_t column);

    void getLastNTimeIndex(std::vector<T1>& res,std::uint32_t count);

    /**
     * 获取最近的一缓存
     * @param rec
     */
    void getLastData(std::vector<T2> &rec);

    /***
     * 获取第nDim维度 所有的数据，缓存未满时返回缓存部分
     * @param nDim
     * @return
     */
    std::vector<T2> *getDimData(std::uint32_t nDim);

    /**
     * 获取全部数据
     */
    std::vector<std::vector<T2>> & getAllData();

    int getBufferSize();

    int getCurIndex();

    int getStartIndex();

    void update(std::int32_t row,std::int32_t col,T2 value);

    std::int32_t getBufferCnt();

    T1 getTimeByIndex(std::int32_t index);

    std::vector<T1>& getTimeIndices();
private:
    bool isTimeIndex{};   // 是否缓存时间索引
    std::vector<T1> mTimeIndexBuff; //时间索引
    std::vector<std::vector<T2>> mDataBuffer; //数据缓存
    std::uint32_t mDim{}; //  缓存数据维度
    std::uint32_t mSize{};    // 缓存窗口大小
    int mIndex{};             // 最新对应的buff 的缓存位置
    bool mFull{} ;            //   缓存数据是否超过缓存大小
private:
    void getDataByVecIndex(int vecIndex,std::vector<T2> &res);

};

template<typename T1,typename T2>
int VectorBuffer<T1, T2>::getBufferSize() {
    return mSize;
}

template<typename T1,typename T2>
int VectorBuffer<T1, T2>::getCurIndex() {
    return mIndex;
}

template<typename T1,typename T2>
int VectorBuffer<T1, T2>::getStartIndex()  {
    if(!mFull){
        return mIndex;
    }else{
        fmod(mIndex + mSize + 1,mSize);
    };
}

template<typename T1,typename T2>
std::int32_t VectorBuffer<T1,T2>::getBufferCnt() {
    if(!mFull){
        return mIndex + 1;
    }else{
        return mSize;
    }
}

template<typename T1,typename T2>
T1 VectorBuffer<T1, T2>::getTimeByIndex(std::int32_t index) {
    return mTimeIndexBuff[index];
}

template<typename T1,typename T2>
std::vector<T1>& VectorBuffer<T1, T2>::getTimeIndices() {
    return mTimeIndexBuff;
}



template<typename T1,typename T2>
VectorBuffer<T1, T2>::VectorBuffer(std::uint32_t dims, std::uint32_t size, bool isTimeIdex) {
    this->mDim = dims;
    this->mSize = size;
    this->isTimeIndex = isTimeIdex;
}
template<typename T1,typename T2>
void VectorBuffer<T1, T2>::init() {
    this->mIndex = -1;
    this->mFull = false;
    this->mDataBuffer.resize(mDim);
    for(auto n = 0;n < mDim ;n++){
        mDataBuffer[n].reserve(mSize);
    }
    if(isTimeIndex){
        this->mTimeIndexBuff.reserve(mSize);
    }
}

template<typename T1,typename T2>
VectorBuffer<T1, T2>::~VectorBuffer() = default;

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::addData(std::vector<T2> data) {
    mIndex = fmod(mIndex +1,mSize);
    for(std::uint32_t i = 0;i<mDim;i++){
        if(!isFull()){
            this->mDataBuffer[i].push_back(data[i]);
        }else{
            this->mDataBuffer[i][mIndex] = data[i];
        }
    }
    if(!mFull && mIndex + 1 == mSize){
        mFull = true;
    }
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::addData(T1 timeIndex, std::vector<T2> data) {
    mIndex = fmod(mIndex + 1,mSize);
    if(isFull()){
        this->mTimeIndexBuff[mIndex] = timeIndex;
    }else{
        this->mTimeIndexBuff.push_back(timeIndex);
    }
    mIndex = fmod(mIndex -1,mSize);
    addData(data);
}


template<typename T1,typename T2>
bool VectorBuffer<T1, T2>::isFull() {
    return mFull;
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getDataByTimeIndex(T1 timeIndex, std::vector<T2> &ret) {
    std::uint32_t vec_index = -1;
    for(std::uint32_t i= 0;i<(isFull()?mSize:mIndex+1);i++){
        if(mTimeIndexBuff[i] == timeIndex){
            vec_index = i;
            break;
        }
    }
    getDataByVecIndex(vec_index,ret);
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getDataByVecIndex(int vecIndex, std::vector<T2> &res) {
    res.clear();
    if(vecIndex >= 0){
        for(std::int32_t i = 0;i<mDim;i++){
            res.push_back(mDataBuffer[i][vecIndex]);
        }
    }
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getDataByIndexFromLast(std::uint32_t index, std::vector<T2> &ret) {
    if((isFull() && index <= mSize) || (!isFull() && index <= mIndex +1)){
        int vecIndex = mIndex - index + 1;
        vecIndex = vecIndex < 0 ? vecIndex + mSize :vecIndex;
        getDataByVecIndex(vecIndex,ret);
    }
}


template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getLastData(std::vector<T2> &rec) {
    getDataByVecIndex(mIndex,rec);
}

template<typename T1,typename T2>
std::vector<T2> *VectorBuffer<T1, T2>::getDimData(std::uint32_t nDim) {
    if(mDim > nDim){
        return &mDataBuffer[nDim];
    }else{
        return nullptr;
    }
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::update(std::int32_t row, std::int32_t col, T2 value) {
    if(row >=0 && row < mDim && col >=0 && col < mSize){
        mDataBuffer[row][col] = value;
    }
}

template<typename T1,typename T2>

void VectorBuffer<T1, T2>::clear() {
    mTimeIndexBuff.clear();
    mDataBuffer.clear();
    mIndex = -1;
    mFull = false;
}

template<typename T1,typename T2>
void VectorBuffer<T1,T2>::reset() {
    clear();
    init();
}

template<typename T1,typename T2>
std::vector<std::vector<T2>>& VectorBuffer<T1, T2>::getAllData() {
    return mDataBuffer;
}
template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getLastNDataByColumnIndex(std::vector<T2>& res,std::uint32_t count,std::uint32_t columnId){
    if(isFull()){
        count = mSize >= count ? count : mSize;
    }else{
        count = mIndex+1 >= count ? count : mIndex+1;
    }
    for(int i=0;i<count;i++){
        auto index = mIndex - i;
        if(index < 0){
            index = mSize + index;
        }
        res.emplace_back(mDataBuffer.at(columnId).at(index));
    }
}

template<typename T1,typename T2>
void VectorBuffer<T1, T2>::getLastNTimeIndex(std::vector<T1>& res,std::uint32_t count){
    if(isFull()){
        count = mSize >= count ? count : mSize;
    }else{
        count = mIndex+1 >= count ? count : mIndex+1;
    }
    for(int i=0;i<count;i++){
        auto index = mIndex - i;
        if(index < 0){
            index = mSize + index;
        }
        res.emplace_back(mTimeIndexBuff.at(index));
    }
}

END_SPACE_LANGE_VDR
#endif //LANGGEBASE_VECTOR_BUFF_H
